//! @Author: DengLibin
//! @Date: Create in 2024-01-17 18:26:52
//! @Description: csp  接口 进行rsa加密和解密

#[cfg(windows)]
extern crate winapi;

use winapi::um::errhandlingapi::GetLastError;
use winapi::um::winbase::FormatMessageA;
use winapi::um::winbase::FORMAT_MESSAGE_ALLOCATE_BUFFER;
use winapi::um::winbase::FORMAT_MESSAGE_FROM_SYSTEM;
use winapi::um::wincrypt::CryptAcquireContextA;

use winapi::um::wincrypt::CryptReleaseContext;

use winapi::um::wincrypt::HCRYPTPROV;

use winapi::shared::minwindef::BOOL;
use winapi::shared::minwindef::DWORD;

use winapi::um::winnt::LANG_NEUTRAL;
use winapi::um::winnt::MAKELANGID;
use winapi::um::winnt::SUBLANG_DEFAULT;

use std::ptr::null_mut;

use rust_common::base64;
use winapi::{
    shared::winerror::{
        ERROR_BUSY, ERROR_NOT_ENOUGH_MEMORY, NTE_BAD_FLAGS, NTE_BAD_KEYSET, NTE_KEYSET_ENTRY_BAD,
        NTE_KEYSET_NOT_DEF, NTE_NO_MEMORY, NTE_PROV_DLL_NOT_FOUND,
    },
    um::wincrypt::{CryptDecrypt, CryptEncrypt, CryptGetUserKey, AT_KEYEXCHANGE, HCRYPTKEY},
};

// CSP(加密服务提供商名称)
const PROVIDER_NAME: &str = "EnterSafe ePass3000GM CSP v1.0";

// usbkey中密钥容器名称
const CONTAINER: &str = "yiscn";

/// @Author: DengLibin
/// @Date: Create in 2024-01-18 11:12:43
/// @Description: rsa加解密
#[cfg(windows)]
pub fn hello_encrypt() {
    use winapi::um::wincrypt::{CryptDestroyKey, CryptExportKey, PROV_RSA_FULL, PUBLICKEYBLOB};

    use crate::encrypt;

    let mut sz_provider = PROVIDER_NAME.as_bytes().to_vec();
    //加一个0结尾
    sz_provider.push(0);

    //转i8
    let provider_str = sz_provider
        .iter()
        .map(|item| *item as i8)
        .collect::<Vec<i8>>();
    //转指针
    let provider = provider_str.as_ptr();
    //清理
    drop(sz_provider);

    let mut sz_container = CONTAINER.as_bytes().to_vec();
    //加一个0结尾
    sz_container.push(0);

    //转i8
    let sz_container_str = sz_container
        .iter()
        .map(|item| *item as i8)
        .collect::<Vec<i8>>();
    //转指针
    let sz_container_p = sz_container_str.as_ptr();
    //清理
    drop(sz_container);

    unsafe {
        // 定义加密上下文句柄
        let mut hprov: HCRYPTPROV = 0;
        let hp = &mut hprov;
        //获取上下文句柄
        let b: BOOL = CryptAcquireContextA(hp, sz_container_p, provider, PROV_RSA_FULL, 0);
        println!("初始化上下文结果：{},句柄:{}", b, *hp);

        let success: bool = b != 0;
        if !success {
            let error_code = GetLastError();
            if error_code as i32 == NTE_BAD_KEYSET {
                println!("无法打开密钥容器或容器不存在");
            } else if error_code == ERROR_NOT_ENOUGH_MEMORY {
                println!("操作系统在操作期间内存不足");
            } else if error_code == ERROR_BUSY {
                println!("另一个线程或进程正在使用此密钥容器");
            } else if error_code as i32 == NTE_KEYSET_ENTRY_BAD {
                println!("找到 pszContainer 密钥容器，但已损坏");
            } else if error_code as i32 == NTE_KEYSET_NOT_DEF {
                println!("请求的提供程序不存在。");
            } else if error_code as i32 == NTE_NO_MEMORY {
                println!("CSP 在操作期间内存不足。");
            } else if error_code as i32 == NTE_PROV_DLL_NOT_FOUND {
                println!("提供程序 DLL 文件不存在或不在当前路径上。");
            } else if error_code as i32 == NTE_BAD_FLAGS {
                println!("dwFlags 参数的值无效。");
            } else
            //容器已存在
            if error_code == 0x8009000F {
                println!("容器已存在:{}", CONTAINER);
            }
        }

        // 成功
        if success {
            //获取加密key
            let mut h_key: HCRYPTKEY = 0;

            if CryptGetUserKey(hprov, AT_KEYEXCHANGE, &mut h_key) == 0 {
                println!("获取加密key错误");
                show_error();
            } else {
                println!("获取加密key成功:{}", h_key);
            }

            //加密字符串
            let content = "abcedfg";
            //转vec 缓冲区
            let mut content_v = content.as_bytes().to_vec();

            let real_data_len: DWORD = content_v.len() as u32;

            //内容长度,这个变量是可变的，接收函数输出
            let mut data_len: DWORD = real_data_len;
            //缓冲区大小
            let mut buff_len = data_len;
            println!("数据长度:{}", data_len);

            //第一次加密,数据传空,只给数据大小，计算 加密后的大小，完成后 ata_len变为数据加密后的大小
            if CryptEncrypt(h_key, 0, 1, 0, null_mut(), &mut data_len, buff_len) == 0 {
                println!("第一次加密错误");
                show_error();
            } else {
                //更新缓冲区大小为加密后的数据大小
                buff_len = data_len;
                //扩大缓冲区到加密后的长度
                for _ in real_data_len..buff_len {
                    content_v.push(0);
                }

                //待加密数据指针
                let content_p = content_v.as_mut_ptr();
                //数据长度还原为真实数据长度
                data_len = real_data_len;
                //第二次加密数据, 加密后data_len改为加密后的长度
                if CryptEncrypt(h_key, 0, 1, 0, content_p, &mut data_len, buff_len) == 0 {
                    println!("第二次加密错误");
                    show_error();
                } else {
                    println!("第二次加密成功,data_len:{}", data_len);

                    //加密后的数据，字节序列是反的，用java解密要反转一下
                    println!("加密数据:{}", base64::encode_bytes(&content_v[..]));
                    println!("解密数据");
                    
                    //使用外部加密的数据
                    //公钥加密的数据
                    let encrypt_data = "TGoiCFSxqI1czSN8K2MIio72z0TLU2BigYmGNZATdad/bNGsaFmvvyz/3QVTpkXW/9+IQb47YSjl9nOQriWhEZjIU33C8Jfw6qkseopjL+1VYw5m7kAe013blsC3OunPyx2ZRDFaWgPNzBip61AqK9wa4LtMdWrF8Bxxj9SRKZMTp3G2lCkh85UkW2Jgmh1DChtHmpGEox5rJTTntLoTBRf0JKtc+EAp6j7r+3OMUhlUnXPSZkwhvBbEB8s0MCNyO/G7NzLJ/O6DRMY2X61zGyAxLPb7XKUKuQKhQVjjyuvzLif+ock+rgPx35MlnurPsxZBh3um4EBvh8UeVAXQdg==";
                    let mut content_v = base64::decode_to_bytes(encrypt_data).unwrap();
                    //反转
                    let l = content_v.len();
                    for i in 0..l/2 {
                        let temp = content_v[i];
                        content_v[i] = content_v[l - 1 - i];
                        content_v[l - 1 - i] = temp;
                    }
                    let content_p = content_v.as_mut_ptr();
                    data_len = content_v.len() as u32;



                    if CryptDecrypt(h_key, 0, 1, 0, content_p, &mut data_len) == 0 {
                        println!("解密数据错误");
                        show_error();
                    } else {
                        let s = &content_v[0..data_len as usize];
                        let content = std::str::from_utf8(s).unwrap();
                        println!("解密数据成功:{}, 长度:{}", content, data_len);
                    }
                }

                //第一次导出密钥，获取长度
                let mut dw_blob_len: DWORD = 0;
                if CryptExportKey(h_key, 0, PUBLICKEYBLOB, 0, null_mut(), &mut dw_blob_len) == 0
                //public key blob length
                {
                    println!("第一次导出密钥失败");
                    show_error();
                } else {
                    println!("第一次导出密钥成功,长度:{}", dw_blob_len);
                    //根据长度创建缓冲区
                    let mut key_buf = vec![0; dw_blob_len as usize];
                    if CryptExportKey(
                        h_key,
                        0,
                        PUBLICKEYBLOB,
                        0,
                        key_buf.as_mut_ptr(),
                        &mut dw_blob_len,
                    ) == 0
                    {
                        println!("第二次导出密钥失败");
                        show_error();
                    } else {
                        println!("第二次导出密钥成功,长度:{}", dw_blob_len);

                        println!(
                            "第二次导出密钥成功:{}",
                            base64::encode_bytes(&key_buf[..dw_blob_len as usize])
                        );
                    }
                }

                println!("释放加密key句柄");
                if CryptDestroyKey(h_key) == 0 {
                    println!("释放加密key句柄失败");
                    show_error();
                } else {
                    println!("释放加密Key句柄成功");
                }
            }

            let b: BOOL = CryptReleaseContext(hprov, 0);
            println!("释放结果:{}", b);
        } else {
            println!("获取上下文句柄错误");
            show_error();
        }
    }
}

#[allow(dead_code)]
fn show_error() {
    unsafe {
        let error_code = GetLastError();
        println!("出错了:错误码:{0:#x}", error_code);

        let mut buffer = vec![0; 100];

        let dw_language_id = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) as u32;
        //MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) as u32
        let r = FormatMessageA(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
            core::ptr::null_mut(),
            error_code,
            dw_language_id,
            buffer.as_mut_ptr(),
            0,
            core::ptr::null_mut(),
        );
        let buf = buffer.iter().map(|i| *i as u8).collect::<Vec<u8>>();
        println!(
            "错误信息:{}",
            std::str::from_utf8(&buf[..r as usize]).unwrap()
        );
    }
}
